﻿using System.ComponentModel;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using System.Windows.Media;
using System;
using System.Collections.Generic;

namespace VS.Infrastructure.Controls
{
    [TemplatePart(Name = XamlControl.ContentElementName, Type = typeof(ContentControl))]
    public class XamlControl : Control
    {
        public event EventHandler<XamlLoadedEventArgs> XamlLoaded;

        #region Fields
        private Assembly _sourceAssembly = Assembly.GetCallingAssembly();
        #endregion

        #region Template Parts

        private const string ContentElementName = "PART_ContentElement";
        private ContentControl _contentElement { get; set; }

        #endregion

        #region SourceProperty

        public string SourceAssembly
        {
            get { return (string)GetValue(SourceAssemblyProperty); }
            set { SetValue(SourceAssemblyProperty, value); }
        }

        public static readonly DependencyProperty SourceAssemblyProperty =
            DependencyProperty.Register("SourceAssembly", typeof(string), typeof(XamlControl), new PropertyMetadata(Assembly.GetCallingAssembly().FullName, new PropertyChangedCallback(SourceAssemblyProperty_Changed)));

        private static void SourceAssemblyProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            //XamlControl c = d as XamlControl;
            //if (c != null && e.NewValue != e.OldValue)
            //{
            //    c._sourceAssembly = Assembly.Load(e.NewValue as string);
            //}
        }

        #endregion

        #region UriProperty

        public string Uri
        {
            get { return (string)GetValue(UriProperty); }
            set { SetValue(UriProperty, value); }
        }

        public static readonly DependencyProperty UriProperty =
            DependencyProperty.Register("Uri", typeof(string), typeof(XamlControl), new PropertyMetadata(null));

        #endregion

        #region Ctor
        public XamlControl()
        {
            this.DefaultStyleKey = typeof(XamlControl);
        }
        #endregion

        #region Methods

        public override void OnApplyTemplate()
        {
            _contentElement = GetTemplateChild(XamlControl.ContentElementName) as ContentControl;

            try
            {
                _sourceAssembly = Assembly.Load(SourceAssembly);
                FrameworkElement element = LoadXaml(_sourceAssembly) as FrameworkElement;
                _contentElement.Content = element;
                if (XamlLoaded != null)
                    XamlLoaded(this, new XamlLoadedEventArgs(element));
            }
            catch (Exception e)
            {
                List<string> messages = new List<string>()
                {
                    "SourceAssembly=" + SourceAssembly,
                    string.IsNullOrEmpty(Uri) ? "Uri=Not set." : "Uri=" +  Uri,
                    e.Message,
                    e.InnerException != null ? e.InnerException.Message : "No more messages."
                };
                _contentElement.Content = new ItemsControl() { ItemsSource = messages };
            }

            base.OnApplyTemplate();
        }

        private object LoadXaml(Assembly assembly)
        {
            Stream xaml = assembly.GetManifestResourceStream(Uri);
            using (StreamReader tr = new StreamReader(xaml))
            {
                return XamlReader.Load(tr.ReadToEnd());
            }
        }

        #endregion
    }

    public class XamlLoadedEventArgs : EventArgs
    {
        public FrameworkElement Element { get; private set; }

        public XamlLoadedEventArgs(FrameworkElement element)
        {
            Element = element;
        }

    }
}

